const axios = require("axios");
const fs = require("fs");
const https = require("https");
const uuid = require("uuid");
const sharp = require("sharp");

const userAgents = [
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.76 Safari/537.36",
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 17_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
  "Mozilla/5.0 (Linux; Android 14; SM-S918B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.69 Mobile Safari/537.36",
  "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:110.0) Gecko/20100101 Firefox/110.0",
  "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko",
  "Mozilla/5.0 (iPad; CPU OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
  "Opera/9.80 (Android 14; SM-A546B) Presto/2.12.456 Version/12.18",
  "Mozilla/5.0 (Linux; Android 11; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.78 Mobile Safari/537.36 EdgA/116.0.1938.0",
  "Mozilla/5.0 (PlayStation 5; PlayStation 5/OS 11.0.0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15",
];

const stringtifyUrl = (url, params) => {
  const search = Object.entries(params)
    .map(([key, value]) => {
      return `${key}=${encodeURIComponent(value)}`;
    })
    .join("&");
  return [url, search].join("?");
};

async function fetchImageUrl(userAgent, word, page = 1) {
  const url = stringtifyUrl("https://image.baidu.com/search/acjson", {
    tn: "resultjson_com",
    word,
    pn: (page - 1) * 30,
    imgratio: 4,
    hd: 1,
  });
  const { data } = await axios.get(url, {
    headers: {
      "User-Agent": userAgent,
    },
  });
  const { data: rets } = data || {};
  if (!Array.isArray(rets)) return [];
  return rets.reduce((rets, item) => {
    const { thumbURL, replaceUrl } = item || {};
    const [replaceUrlItem] = replaceUrl || [];
    const { ObjURL } = replaceUrlItem || {};

    if (thumbURL && ObjURL) {
      return [...rets, { thumbURL, ObjURL }];
    }
    return rets;
  }, []);
}

async function fetchImageUrls(words, pages = 1) {
  const images = [];
  for await (const word of words) {
    for await (const [page] of Array(pages).entries()) {
      const delay = Math.floor(Math.random() * 3 + 1) * 1000;
      console.log("图片地址获取间隔时间: ", delay);
      await new Promise((resolve) => setTimeout(resolve, delay));
      const userAgent =
        userAgents[Math.floor(Math.random() * userAgents.length)];
      const _images = await fetchImageUrl(userAgent, word, page + 1);
      images.push(..._images);
    }
  }
  return images;
}

// fetchImageUrls(["赵丽颖", "白冰"]).then((data) => {
//   console.log("data: ", data);
//   console.log("data: ", data.length);
// });

async function fetchImage(url, saveDir) {
  const { data } = await axios
    .get(url, {
      responseType: "stream",
      headers: {
        "User-Agent": userAgents[Math.floor(Math.random() * userAgents.length)],
      },
    })
    .catch(() => {
      return Promise.reject("Image request failed!");
    });
  const { headers = {} } = data || {};

  const [fileType = ""] = (headers?.["content-type"] || "").split(";");
  const [_, imageType] = (fileType || "").split("/");
  if (imageType !== "jpeg") {
    return Promise.reject("The image format is incorrect!");
  }

  const file = `${saveDir}/${uuid.v4(12)}.${imageType}`;
  const writer = fs.createWriteStream(file);
  data.pipe(writer);
  await new Promise((resolve) => writer.on("finish", resolve));
  const metadata = await sharp(file)
    .metadata()
    .catch(() => Promise.reject("Image content acquisition failed!"));
  return metadata;
}

async function fetchImages(words, pages, dir, delDir = true) {
  const imageUrls = await fetchImageUrls(words, pages);
  console.log("待下载图片数量: ", imageUrls.length);

  const poll = async (images, len, dir) => {
    let ans = 0;
    const pools = new Set();

    for (let n = 0; n < images.length; n++) {
      const promise = fetchImage(images[n], dir)
        .then(() => {
          ans++;
        })
        .catch((error) => {
          console.log("图片获取失败!", error.toString());
        })
        .finally(() => {
          pools.delete(promise);
        });
      pools.add(promise);
      if (pools.size >= len) {
        await Promise.race(pools);
      }
    }
    await Promise.all(pools);
    return ans;
  };

  const images = imageUrls.map((item) => item["ObjURL"]);
  if (fs.existsSync(dir) && delDir) {
    fs.readdirSync(dir).forEach((file) => {
      fs.unlinkSync(`${dir}/${file}`);
    });
    fs.rmdirSync(dir);
  }
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
  const ans = await poll(images, 3, dir);
  console.log("成功下载的图片数量：", ans);
  process.exit(0);
}

fetchImages(
  [
    "唐嫣",
    "戚薇",
    "杨紫",
    "虞书欣",
    "柳岩",
    "章若楠",
    "唐艺昕",
    "景甜",
    "虞书欣",
    "文咏珊",
    "周秀娜",
    "卫诗雅",
    "白冰",
    "倪妮",
    "白鹿",
    "赵丽颖",
    "杨蓉",
    "刘亦菲",
    "周冬雨",
    "赵今麦",
    "李庚希",
    "张雪迎",
    "关晓彤",
    "赵思露",
  ]
    .slice(0)
    .map((item) => `${item}超清电脑壁纸`),
  2,
  "D:/图库/女星超清壁纸集合",
  true
);
